package middleware

import (
	"context"
	"net/http"

	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"ldaccount/pkg/lueerror"
)

// ToGRPCErr 转换成功grpc error
func lueerrGRPCErr(le lueerror.LueError) (error, bool) {
	switch le.HttpStatus() {
	case http.StatusOK:
		return nil, false
	case http.StatusBadRequest:
		return status.Error(codes.InvalidArgument, le.Error()), le.SendMail()
	case http.StatusRequestTimeout, http.StatusBadGateway:
		return status.Error(codes.DeadlineExceeded, le.Error()), le.SendMail()
	case http.StatusNotFound:
		return status.Error(codes.NotFound, le.Error()), le.SendMail()
	case http.StatusConflict:
		return status.Error(codes.AlreadyExists, le.Error()), le.SendMail()
	case http.StatusForbidden:
		return status.Error(codes.PermissionDenied, le.Error()), le.SendMail()
	case http.StatusInsufficientStorage:
		return status.Error(codes.ResourceExhausted, le.Error()), le.SendMail()
	case http.StatusPreconditionFailed, http.StatusUnprocessableEntity, http.StatusPreconditionRequired:
		return status.Error(codes.FailedPrecondition, le.Error()), le.SendMail()
	case http.StatusNotAcceptable:
		return status.Error(codes.Aborted, le.Error()), le.SendMail()
	//case http.StatusRequestedRangeNotSatisfiable:
	//	return status.Error(codes.OutOfRange, le.Error()), le.SendMail()
	case http.StatusNotImplemented:
		return status.Error(codes.Unimplemented, le.Error()), le.SendMail()
	case http.StatusInternalServerError:
		return status.Error(codes.Internal, le.Error()), le.SendMail()
	case http.StatusServiceUnavailable:
		return status.Error(codes.Unavailable, le.Error()), le.SendMail()
	//case http.StatusGone:
	//	return status.Error(codes.DataLoss, le.Error()), le.SendMail()
	default:
		return status.Error(codes.Unknown, le.Error()), le.SendMail()
	}
}

// ToGRPCError 将 error 转成 grpc 标准错误
func ToGRPCError(err error) (error, bool) {
	_, ok := status.FromError(err)
	if ok {
		return err, true
	}
	errL, ok := err.(lueerror.LueError)
	if !ok {
		return status.Error(codes.Unknown, err.Error()), true
	}
	return lueerrGRPCErr(errL)
}

// GrpcUnaryErrorInterceptor error handler
func GrpcUnaryErrorInterceptor() grpc.UnaryServerInterceptor {
	return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
		resp, err = handler(ctx, req)
		if err != nil {
			errRpc, mailErr := ToGRPCError(err)
			if mailErr {
				sendMail(ctx, errRpc, "GRPC")
			}
			return nil, errRpc
		}
		return resp, nil
	}
}
